\subsection{Доступ к аргументам и локальным переменным вызывающей ф-ции}

Из основ \CCpp мы знаем, что иметь доступ к аргументам ф-ции или её локальным переменным --- невозможно.

Нем не менее, при помощи грязных хаков это возможно.
Например:

\begin{lstlisting}[style=customc]
#include <stdio.h>

void f(char *text)
{
	// распечатать стек
	int *tmp=&text;
	for (int i=0; i<20; i++)
	{
		printf ("0x%x\n", *tmp);
		tmp++;
	};
};

void draw_text(int X, int Y, char* text)
{
	f(text);

	printf ("Собираемся нарисовать [%s] на %d:%d\n", text, X, Y);
};

int main()
{
	printf ("адрес main()=0x%x\n", &main);
	printf ("адрес draw_text()=0x%x\n", &draw_text);
	draw_text(100, 200, "Hello!");
};
\end{lstlisting}

На 32-битной Ubuntu 16.04 и GCC 5.4.0, я получил это:

\begin{lstlisting}
адрес main()=0x80484f8
адрес draw_text()=0x80484cb
0x8048645	первый аргумент f()
0x8048628
0xbfd8ab98
0xb7634590
0xb779eddc
0xb77e4918
0xbfd8aba8
0x8048547	адрес возврата в середину main()
0x64		первый аргумент draw_text()
0xc8		второй аргумент draw_text()
0x8048645	третий аргумент draw_text()
0x8048581
0xb779d3dc
0xbfd8abc0
0x0
0xb7603637
0xb779d000
0xb779d000
0x0
0xb7603637
\end{lstlisting}

(Комментарии мои.)

Так как \IT{f()} начинает перебирать элементы стека начиная со своего первого аргумента, первый элемент стека это
действительно указатель на строку \q{Hello!}.
Мы видим что её адрес также используется как третий аргумент для ф-ции \IT{draw\_text()}.

В \IT{f()} мы можем читать аргументы и локальные переменные ф-ций, если мы точно знаем разметку стека, но она все время
меняется, от компилятора к компилятору.
Различные уровни оптимизаций также сильно влияют на разметку.

Но если мы можем каким-то образом распознать нужную нам информацию, мы даже можем модифицировать её.
Как пример, я переработаю ф-цию \IT{f()}:

\begin{lstlisting}[style=customc]
void f(char *text)
{
	...

	// найти пару переменных 100, 200 и модифицировать вторую
	tmp=&text;
	for (int i=0; i<20; i++)
	{
		if (*tmp==100 && *(tmp+1)==200)
		{
			printf ("нашли\n");
			*(tmp+1)=210; // поменять 200 на 210
			break;
		};
		tmp++;
	};
};
\end{lstlisting}

Таки работает:

\begin{lstlisting}
нашли
Собираемся нарисовать [Hello!] на 100:210
\end{lstlisting}

\myparagraph{Summary}

Это экстремально грязный хак, предназначенный для демонстрации внутренностей стека.
я никогда даже не видел и не слышал чтобы кто-то использовал такое в реальном коде.
Но это, как всегда, хороший пример.

\myparagraph{\Exercise}

Этот пример был скомпилирован без оптимизации на 32-битной Ubuntu используя GCC 5.4.0 и он работает.
Но когда я включил максимальную оптимизацию (\TT{-O3}), всё перестало работать.
Попробуйте разобраться, почему.

Используйте свой любимый компилятор и OS, попробуйте разные уровни оптимизации, узнайте, заработает или нет,
если нет, попробуйте понять, почему.

